package minijvm.engine;

import minijvm.clz.ClassFile;
import minijvm.constant.MethodRefInfo;
import minijvm.loader.ClassFileLoader;
import minijvm.method.Method;

import java.util.HashMap;
import java.util.Map;

/**
 * 模拟 java内存模型中的 方法区
 *
 * @author ChangLiang
 * @date 2020/4/28
 */
public class MethodArea {

    /**
     * 单例模式 饿汉式
     */
    public static final MethodArea instance = new MethodArea();

    /**
     * 使用一个HashMap来模拟方法区
     */
    Map<String, ClassFile> map = new HashMap<>();

    /**
     * 注意：我们做了极大的简化， ClassLoader 只有一个， 实际JVM中的ClassLoader,是一个双亲委托的模型
     */
    private ClassFileLoader clzLoader = null;

    private MethodArea(){}

    public static MethodArea getInstance(){
        return instance;}

    public void setClzLoader(ClassFileLoader clzLoader) {
        this.clzLoader = clzLoader;
    }

    public Method getMainMethod(String className) {
        ClassFile clzFile = this.findClassFile(className);
        return clzFile.getMainMethod();
    }

    public Method getMethod(MethodRefInfo methodRefInfo) {
        String methodName = methodRefInfo.getMethodName();
        String className = methodRefInfo.getClassName();
        String paramAndReturnType = methodRefInfo.getParamAndReturnType();
        return this.getMethod(className, methodName, paramAndReturnType);
    }

    /**
     * 在方法区中根据className获取ClassFile
     * @param className
     * @return
     */
    public ClassFile findClassFile(String className) {
        if (map.get(className) != null) {
            return map.get(className);
        }
        // in class not loaded lockcondition
        ClassFile classFile = this.clzLoader.loadClass(className);
        // 把classFile对象 放到 方法区中
        map.put(className, classFile);
        return classFile;
    }

    private Method getMethod(String className, String methodName, String paramAndReturnType) {
        ClassFile classFile = this.findClassFile(className);
        Method method = classFile.getMethod(methodName, paramAndReturnType);
        return method;
    }


}
